// ==UserScript== // @name 💡WebPreview - 信息直达 // @namespace https://ez118.github.io/ // @version 1.3.0 // @description 支持国内主流搜索引擎的搜索结果快速预览(直达网页大纲)。只需点击搜索结果旁的小灯泡按钮,即可在右侧速览窗中快速查看目标网站所含的图片、链接、标题大纲、文本。 // @author ZZY_WISU // @match *://*/* // @connect * // @license GNU GPLv3 // @icon data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACMAAAAjCAMAAAApB0NrAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAADZQTFRFAAAAn8LgEG6+SZDMg7HaZaDSgrHZkLrdO4jJZqHTgbLZHnbCdKnWLX/FV5jPLX7FSY/LdKnVpsJ+6QAAABJ0Uk5TACb//8j/yoP//8n/8f/////yflwd4QAAAORJREFUeJy1k9EagyAIhfVYGqnV3v9lp2kLjdrFvnGT4Q8coJTqTMP0rov9nRnYebTn2Z3HCSSGzvAsvwjNACuQIH1lGiRBNU+IALwpAXq4hCUCh0VR3y69ykrZbqCFdTHJUNLd5JRGGeH4q4fAdNkDwgWxWLqY6eSJKBcZYTtmz5tuSa1pGkZkUBrJT621WL/U0vW6+nyDkLRm3/YOqXfXeKP8SRGb0M0u+AV14poCZUlaFNMK3YQ9fGwtjLjPwzaYPPynUomp9shQHv4XZl/Oz8yCGGwwj4yKRbL08zGz48t1rjcZWATm0KKJdwAAAABJRU5ErkJggg== // @run-at document-end // @grant GM_xmlhttpRequest // @grant GM_download // @grant GM_registerMenuCommand // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @require https://update.greasyfork.org/scripts/499192/1402326/jquery_360.js // ==/UserScript== var iconImg = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAUCAMAAACK2/weAAAAAXNSR0IB2cksfwAAAAlwSFlzAAALEwAACxMBAJqcGAAAAHtQTFRFAAAAOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGofOGoffJU8/QAAACl0Uk5TABWJvOy7hhRd8P/tT25TIfzzlXziyPju8c/NgHgY9OMRZvU2WkPQx8o0T8eSAAAAbUlEQVR4nI3OyQ6CQBBF0auASOOEgICoCKLw/19ImqG7TFx4V3UWLymA1dpxXW/jM7YN1Fi409or0wGOJ8vI56xEMYlkykUyI5cMKCSvlJI37g+r6gm1UfPSb7UL39PTC/nJz6SOv/qazuNeXwMWhAmHAXFPJgAAAABJRU5ErkJggg=="; /* 用于存储小灯泡按钮的图片数据 */ const contentEleSelList = { "blog.csdn.net": "#article_content", "zhuanlan.zhihu.com": ".Post-RichTextContainer", "jingyan.baidu.com": "#format-exp", "www.bilibili.com": "#article-content", "zhidao.baidu.com": "#qb-content", "www.cnblogs.com": "#topics", "www.sohu.com": "#mp-editor" }; /* 用于储存指定网站的内容所在父元素(特定博客网站内容优化) */ const VideoSupport = [ ["https://v.youku.com/v_show/*.html", "https://player.youku.com/embed/*"], ["https://v.qq.com/x/page/*.html", "https://v.qq.com/txp/iframe/player.html?vid=*"], ["https://www.bilibili.com/video/BV*/", "https://www.bilibili.com/blackboard/html5mobileplayer.html?bvid=*"], ["https://www.bilibili.com/video/av*/", "https://www.bilibili.com/blackboard/html5mobileplayer.html?aid=*"] ]; /* 用于存储阅读器支持直接播放视频的网站及其嵌入播放器代码 */ /* ============================================= */ /** * 生成随机数 * @param len 长度 * @constructor */ function randomString(len) { len = len || 32; var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678'; var maxPos = $chars.length; var pwd = ''; for (let i = 0; i < len; i++) { pwd += $chars.charAt(Math.floor(Math.random() * maxPos)); } return pwd; } /** * 标题元素 * @param tag 标签,h1 ==> 1 , h2 ==> 2 * @param title 标题 * @param level 层级 * @param id 随机生成的id * @constructor */ function TitleElement(tag, title, level, id) { this.tag = tag; this.title = title; this.level = level; this.id = id; } /* 是否是标题元素 */ function isTitleTag(tag) { return tag.is("h1, h2, h3, h4, h5, h6, h7"); } /** * 生成大纲 * @param $articleContent 文章容器 * @constructor */ function getOutline($articleContent) { $articleContent = $($articleContent); /** 全部元素 */ var $eles = $articleContent.find("*"); /** 标题元素列表 */ var titleElementArr = new Array(); /** 上一个元素 */ var preTitleElement = null; $.each($eles, function(index, item) { if (isTitleTag($(item))) { var id = randomString(20); var level = 1; var tag = parseInt($(item).get(0).tagName.replace('h', "").replace('H', "")); var title = $(item).text(); if (null != preTitleElement) { var tagPre = preTitleElement.tag; var levelPre = preTitleElement.level; if (tagPre > tag) { level = levelPre - 1; } else if (tagPre < tag) { level = levelPre + 1; } else { level = levelPre; } } if (title.trim().length > 0) { $(item).attr("id", id); var titleElement = new TitleElement(tag, title, level, id); titleElementArr.push(titleElement); preTitleElement = titleElement; } } }) console.log(titleElementArr); return titleElementArr; } /* ============================================= */ function stringToHtml(str) { var parser = new DOMParser(); var doc = parser.parseFromString(str, 'text/html'); return doc; } function mobileDevice(){ var info = navigator.userAgent; var isPhone = /mobile/i.test(info); return isPhone; } function runAsync(url,send_type,data_ry) { var p = new Promise((resolve, reject)=> { GM_xmlhttpRequest({ method: send_type, url: url, headers: {"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"}, data: data_ry, onload: function(response){resolve(response.responseText);}, onerror: function(response){reject("请求失败");} }); }); return p; } function escapeHtml(str) { const htmlEntities = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }; return str.replace(/[&<>"']/g, (match) => htmlEntities[match]); } function JudgeVideoSupport(url) { var previewFlag = 0; /* 判断是否为支持预览视频的网站 */ for(let i = 0; i < VideoSupport.length; i ++){ if( url.includes( VideoSupport[i][0].split("*")[0] ) ){ return { "state":true, "data":i }; break; } } return { "state":false, "data":-1 }; } function getWebContents(txt) { var links; var images; var content; var outline; /* 获取所有链接 */ /* //这一段代码会把所有链接(包括图片、js、css的链接一并获取) links = txt.match(/href\=\"(https?|http|ftp|file):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/g); for(let i = 0; i < links.length; i ++) { links[i] = links[i].replace("href=\"", ""); } */ links = []; txt.replace(/]*href=['"]([^'"]+)[^>]*>/g,function(match, capture){ links.push(capture); }); /* 获取所有图片 */ images = []; txt.replace(/]*src=['"]([^'"]+)[^>]*>/g,function(match, capture){ images.push(capture); }); content = txt; /* 删除多余空格和换行 */ content = content.replace(/\s+/g, ' ').trim().replace(/(rn|r|n){ 2,}/g, '$1n'); /* 获取文本 */ content = txt.replace(/<\/div>/g, "\n") .replace(/<\/table>/g, "\n") .replace(/<\/h3>/g, "\n") .replace(/<\/p>/g, "

\n") .replace(/<\/li>/g, "\n") .replace(//gis, "") .replace(//gis, "") .replace(//gis, ""); content = content.replace(/<(?!\/?(a|img)\b)[^>]+>/g, ''); /* 删除除了a和img以外的标签 */ content = content.replace(/\r\n/g,"
").replace(/\n/g,"
").replace(/(\s*)+/g, '
'); /* 将换行符变为换行 */ outline = getOutline(txt); //console.log(content); return {"link":links,"image":images,"content":content,"outline":outline}; } function openReader(url) { /* 打开阅读器 */ /* 阅读器加载提示 */ var previewReader = document.getElementById("userscript-webPreviewReader"); previewReader.innerHTML = "

加载中...
" + url + "

"; previewReader.setAttribute("style", "display:block;"); var closeBtn = document.getElementById("userscript-closeBtn"); closeBtn.setAttribute("style", "display:block;"); /* 判断当前链接是支持预览的视频网站,并作出对应处理 */ var SoN = JudgeVideoSupport(url); if(SoN.state == true){ /* 被支持的视频网站的处理 */ var origUrl = url; var frameUrl = ""; url = url.replace(VideoSupport[SoN.data][0].split("*")[0], ""); url = url + "?#"; url = url.split("#")[0].split("?")[0]; url = url.replace(VideoSupport[SoN.data][0].split("*")[1], ""); frameUrl = VideoSupport[SoN.data][1].replace("*", url); previewReader.innerHTML = `
`; /* 淡入 */ $("#FadeInContainer").fadeIn(700); } else { /* 普通网站的处理 */ runAsync(url, "GET", "").then((result)=>{ return result; }).then(function(result){ /* 对指定网站进行内容过滤,指定元素获取 */ const domain = url.split("/")[2]; if (contentEleSelList[domain]) { try { const selector = contentEleSelList[domain]; result = $(result).find(selector).html(); } catch (e) {} } /* 用函数解析网页 */ let reslist = getWebContents(result); let linkhtml = "", imghtml = "", outlinehtml = ""; /* 处理链接列表 */ for(let i = 0; i < reslist.link.length; i ++){ let link_tmp = reslist.link[i]; if(link_tmp.includes("//")){ linkhtml += " 🔗 " + link_tmp + "
"; } } /* 处理图片列表 */ for(let i = 0; i < reslist.image.length; i ++){ imghtml += ""; } /* 处理大纲 */ for(let i = 0; i < reslist.outline.length; i ++){ let space = ""; for(let j = 1; j < reslist.outline[i].level; j ++){ space += "  "; } outlinehtml += space + "+ " + reslist.outline[i].title + "
" } /* 将所有结果添加进阅读器,并显示 */ previewReader.innerHTML = ` `; /* 淡入 */ $("#FadeInContainer").fadeIn(250); }); } /* 执行结束 */ } /* 自动获取搜索结果(测试) */ function checkSearchResults(parentElement) { var classList = []; var countList = []; for(let i = 0; i < parentElement.children.length; i ++) { var child = parentElement.children[i]; var childClass = child.classList; for(let j = 0; j < childClass.length; j ++) { if(classList.indexOf(childClass[j]) !== -1) { /* 对列表中的class出现次数进行计数 */ var p = classList.indexOf(childClass[j]); countList[p] += 1; } else { /* 对列表中未出现的class,插入列表 */ classList.push(childClass[j]); countList.push(0); } } } var countMax = Math.max.apply(null, countList); return (countMax >= 5); } /* 遍历元素 */ function traverseElements(element, callback) { // 如果当前元素没有子元素,直接返回 if (!element || !element.children || element.children.length === 0) { return; } // 调用回调函数处理当前元素 var returnCode = callback(element); //if (returnCode) { return; } /* 如果返回值为true,则代表该元素已包含搜索结果,无需继续遍历 */ // 遍历子元素 for (let i = 0; i < element.children.length; i++) { traverseElements(element.children[i], callback); } } (function() { 'use strict'; var url = window.location.href; var paths = url.split("/"); GM_addStyle(`.userscript-webPreviewBtn{ user-select:none; background-color:#FFFFFFAA; color:#386a1f; padding:6px 18px; font-weight:bold; line-height:16px; height:30px; margin-left:5px; border-radius:30px; border:1px solid #285a0f; cursor:pointer; } .userscript-webPreviewBtn:hover{ background-color:#edf1e5; } .userscript-webPreviewBtn:active{ background-color:#d7e1cd; } .userscript-webPreviewBtn img{ height:16px; } .userscript-closeBtn{ position:fixed; top:calc(8% + 5px); right:26px; z-index:100000; background:#386a1f; color:#FFF; padding:8px 20px; margin:6px; border-radius:30px; font-weight:bold; border:0; border-bottom:1px solid #20460e; cursor:pointer; } .userscript-closeBtn:hover{ background:#487631; } .userscript-webPreviewReader{ font-size:medium; text-align:left; position:fixed; top:8%; right:10px; bottom:0px; z-index:99999; width:35%; height:calc(100% - 8%); min-width:340px; background:#fdfdf6; color:#131f0d; overflow:hidden; box-shadow: 0 0 0 1px rgba(0,0,0,.1), 0 2px 4px 1px rgba(0,0,0,.18); border-radius:15px 15px 0px 0px; } .userscript-webPreviewReader img.error{ display:none; } .ShowList{ margin:0;padding:0;width:100%;cursor:pointer;color:#386a1f; user-select:none; } .image{ height:85px; margin-bottom:8px; margin-right:5px; border-radius:15px; object-fit:contain; max-width:calc(100% - 20px); } .link{ text-decoration:none; color:#386a1f!important; margin-left: 5px; } .link:hover{ text-decoration:underline; } .ImageList, .LinkList, .ContentShow{ padding:16px; margin:8px; background:rgb(216,231,203); border-radius:30px; overflow:hidden; color:#131f0d; box-shadow:0 .5px 1.5px 0 rgba(0,0,0,.19),0 0 1px 0 rgba(0,0,0,.039); } .ContentShow img{ max-width:90%!important; position:relative!important; top:0!important; left:0!important; border-radius:10px; } .ContentShow img::after{ content: ""; display: block; clear: both; } .ContentShow a{ color:#386a1f; text-decoration:underline 1px solid #386a1f; } #videoFrame{ width: calc(100% - 10px); height: calc(100% - 0px); border:1px solid #CCC; border-radius:30px; margin:5px; } #FadeInContainer { overflow-y:scroll; overflow-x:hidden; border-radius:15px 15px 0px 0px; width:100%; height:100%; } `); /* 插入DOM */ /* 阅读器 */ var $previewReader = $('
', { class: 'userscript-webPreviewReader', style: 'display:none;', id: 'userscript-webPreviewReader' }).appendTo('body'); // 创建 closeBtn 元素 var $closeBtn = $('